package com.jic.veteran.service.impl;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.github.pagehelper.PageHelper;
import com.google.common.collect.Lists;
import com.jic.veteran.common.exception.ApiException;
import com.jic.veteran.component.VeteranSecurityContext;
import com.jic.veteran.dao.CmsArticleInfoDao;
import com.jic.veteran.dto.CmsArticleQueryParam;
import com.jic.veteran.dto.CmsArticleShowCountDto;
import com.jic.veteran.mapper.CmsArticleInfoMapper;
import com.jic.veteran.model.CmsArticleInfo;
import com.jic.veteran.model.CmsArticleInfoExample;
import com.jic.veteran.service.CmsArticleService;

import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import com.jic.veteran.service.UmsAdminCacheService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

/**
 * 文章管理Service实现类
 * Created by macro on 2018/10/11.
 */
@Slf4j
@Service
public class CmsArticleServiceImpl implements CmsArticleService {
    @Autowired
    private CmsArticleInfoMapper articleInfoMapper;
    @Autowired
    private CmsArticleInfoDao articleInfoDao;

    @Value("${cms.article.show-count.banner:5}")
    private Integer bannerCount;
    @Value("${cms.article.show-count.news:5}")
    private Integer newsCount;
    @Value("${cms.article.show-count.ads:1}")
    private Integer adsCount;
    @Autowired
    private UmsAdminCacheService umsAdminCacheService;

    @Override
    public List<CmsArticleInfo> list(
            CmsArticleQueryParam queryParam, Integer pageSize, Integer pageNum) {
        PageHelper.startPage(pageNum, pageSize);
        String articleType = queryParam.getArticleType();
        if (StrUtil.isEmpty(articleType)) {
            return Collections.emptyList();
        }
        CmsArticleInfoExample articleInfoExample = new CmsArticleInfoExample();
        CmsArticleInfoExample.Criteria criteria = articleInfoExample.createCriteria();
        criteria.andDeleteStatusEqualTo(false)
                .andArticleTypeEqualTo(articleType.toLowerCase());
        if (StrUtil.isNotEmpty(queryParam.getArticleTitle())) {
            criteria.andArticleTitleLike("%" + queryParam.getArticleTitle() + "%");
        }
        if (ObjectUtil.isNotEmpty(queryParam.getIsShow())) {
            criteria.andIsShowEqualTo(queryParam.getIsShow());
        }
        articleInfoExample.setOrderByClause("is_show desc, publish_time desc");
        return articleInfoMapper.selectByExample(articleInfoExample);
    }

    @Override
    public int saveOrUpdate(CmsArticleInfo articleInfo) {
        Long id = articleInfo.getId();
        return ObjectUtil.isEmpty(id) ? this.create(articleInfo) : this.update(articleInfo);
    }

    @Override
    public int changeStatus(List<Long> ids, String status) {
        if (ObjectUtil.isEmpty(ids)) {
            throw new ApiException("未选中任何需要修改状态的文章");
        }
        CmsArticleInfo cmsArticleInfo = articleInfoMapper.selectByPrimaryKey(ids.get(0));
        if (ObjectUtil.isEmpty(cmsArticleInfo)) {
            throw new ApiException("未找到需要修改状态的文章");
        }
        CmsArticleInfo updater = new CmsArticleInfo();
        if ("disable".equalsIgnoreCase(status)) {
            // 更新为隐藏
            updater.setIsShow(false);
            updater.setPublishTime(null);
        } else {
            CmsArticleInfoExample articleInfoExample = new CmsArticleInfoExample();
            CmsArticleInfoExample.Criteria criteria = articleInfoExample.createCriteria();
            // 查询没显示在首页的信息
            criteria.andDeleteStatusEqualTo(false)
                    .andIsShowEqualTo(false)
                    .andIdIn(ids);
            List<CmsArticleInfo> articleInfoList = articleInfoMapper.selectByExample(articleInfoExample);
            Map<String, List<CmsArticleInfo>> articleInfoGroup
                    = articleInfoList.parallelStream()
                    .collect(Collectors.groupingBy(ai -> ai.getArticleType()
                            .toLowerCase()));

            // 判断显示数量有没有超限
            Map<String, Integer> showCountMap = this.getShowCountMap();
            for (Map.Entry<String, List<CmsArticleInfo>> entry : articleInfoGroup.entrySet()) {
                this.checkShowCount(entry.getKey(), entry.getValue(), showCountMap);
            }
            // 更新为展示
            updater.setIsShow(true);
            updater.setPublishTime(DateUtil.date());
        }
        updater.setModifyBy(VeteranSecurityContext.getUserName());
        updater.setModifyTime(DateUtil.date());

        CmsArticleInfoExample example = new CmsArticleInfoExample();
        example.createCriteria()
                .andDeleteStatusEqualTo(false)
                .andIdIn(ids);
        int update = articleInfoMapper.updateByExampleSelective(updater, example);
        if(update > 0) {
          if ("disable".equalsIgnoreCase(status)) {
              umsAdminCacheService.removeCmsArticleInfoFromList(cmsArticleInfo);
          } else {
              cmsArticleInfo.setIsShow(true);
              cmsArticleInfo.setPublishTime(updater.getPublishTime());
              umsAdminCacheService.setCmsArticleInfoList(cmsArticleInfo);
          }
        }
        return update;
    }

    @Override
    public int delete(List<Long> ids) {
        CmsArticleInfo record = new CmsArticleInfo();
        record.setDeleteStatus(true);
        record.setIsShow(false);
        record.setPublishTime(null);
        CmsArticleInfoExample example = new CmsArticleInfoExample();
        example.createCriteria()
                .andDeleteStatusEqualTo(false)
                .andIdIn(ids);
        int delete = articleInfoMapper.updateByExampleSelective(record, example);
        if(delete >0) {
            CmsArticleInfo cmsArticleInfo = articleInfoMapper.selectByPrimaryKey(ids.get(0));
            if (ObjectUtil.isNotEmpty(cmsArticleInfo)) {
                umsAdminCacheService.removeCmsArticleInfoFromList(cmsArticleInfo);
            }
        }
        return delete;
    }

    @Override
    public CmsArticleInfo detail(Long id) {
        CmsArticleInfo articleInfo = articleInfoMapper.selectByPrimaryKey(id);
        if (articleInfo == null || articleInfo.getDeleteStatus()) {
            throw new ApiException("未找到详情信息");
        }
        return articleInfo;
    }

    private Map<String, Integer> getShowCountMap() {
        List<CmsArticleShowCountDto> showCountHistory = articleInfoDao.getShowCountGroupByType();
        return showCountHistory.parallelStream()
                .collect(Collectors.toMap(
                        CmsArticleShowCountDto::getArticleType,
                        CmsArticleShowCountDto::getShowCount));
    }

    private int create(CmsArticleInfo articleInfo) {
        articleInfo.setDeleteStatus(false);
        articleInfo.setCreateBy(VeteranSecurityContext.getUserName());
        articleInfo.setCreateTime(DateUtil.date());
        articleInfo.setModifyBy(VeteranSecurityContext.getUserName());
        articleInfo.setModifyTime(DateUtil.date());
        if (ObjectUtil.isNotEmpty(articleInfo.getIsShow()) && articleInfo.getIsShow()) {
            articleInfo.setPublishTime(DateUtil.date());
            this.checkShowCount(
                    articleInfo.getArticleType(), Lists.newArrayList(articleInfo), this.getShowCountMap());
        }
        return articleInfoMapper.insert(articleInfo);
    }

    private int update(CmsArticleInfo articleInfo) {
        CmsArticleInfo history = articleInfoMapper.selectByPrimaryKey(articleInfo.getId());
        if (ObjectUtil.isEmpty(history) || history.getDeleteStatus()) {
            return 0;
        }
        articleInfo.setDeleteStatus(false);
        articleInfo.setModifyBy(VeteranSecurityContext.getUserName());
        articleInfo.setModifyTime(DateUtil.date());
        if (ObjectUtil.isNotEmpty(articleInfo.getIsShow()) && articleInfo.getIsShow()) {
            articleInfo.setPublishTime(DateUtil.date());
            if (!history.getIsShow()) {
                this.checkShowCount(
                        articleInfo.getArticleType(), Lists.newArrayList(articleInfo), this.getShowCountMap());
            }
        } else {
            articleInfo.setPublishTime(null);
        }
        return articleInfoMapper.updateByPrimaryKeySelective(articleInfo);
    }

    private void checkShowCount(
            String type, List<CmsArticleInfo> articleInfoList, Map<String, Integer> showCountMap) {
        if (ObjectUtil.isEmpty(articleInfoList)) {
            return;
        }
        Integer existCount = showCountMap.get(type);
        if (ObjectUtil.isEmpty(existCount)) {
            return;
        }
        int newCount = articleInfoList.size() + existCount;
        if ("banner".equalsIgnoreCase(type) && newCount <= bannerCount) {
            return;
        } else if ("news".equalsIgnoreCase(type) && newCount <= newsCount) {
            return;
        } else if ("ads".equalsIgnoreCase(type) && newCount <= adsCount) {
            return;
        }
        throw new ApiException("设置的展示信息超出数量限制");
    }

}
